package com.bianguo.android.ioclibrary;

import android.app.Activity;
import android.util.Log;
import android.view.View;

import com.bianguo.android.ioclibrary.annotations.BindView;
import com.bianguo.android.ioclibrary.annotations.BindViews;
import com.bianguo.android.ioclibrary.annotations.EventBase;
import com.bianguo.android.ioclibrary.handlers.ListenerInvocationHandler;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;

public class ButterKnife {

    public static void bind(Object target) {
        if (target instanceof Activity) {
            Activity activity = (Activity) target;
            View decorView = activity.getWindow().getDecorView();
            bind(target, decorView);
        } else {
            throw new RuntimeException("缺少布局根View");
        }
    }

    public static void bind(Object target, View bindView) {
        bindView(target, bindView);
        bindViews(target, bindView);
        bindClickEvent(target, bindView);
    }

    /**
     * 初始化各个View，即findViewById
     * @param target
     * @param bindView view所在的布局文件最外层View
     */
    private static void bindView(Object target, View bindView) {
        Class<?> clazz = target.getClass();
        if (clazz != null) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                BindView annotation = field.getAnnotation(BindView.class);
                if (annotation != null) {
                    int viewId = annotation.value();
                    Object view = bindView.findViewById(viewId);
                    field.setAccessible(true);
                    try {
                        field.set(target, view);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    private static void bindViews(Object target, View bindView) {
        Class<?> clazz = target.getClass();
        if (clazz != null) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                BindViews annotation = field.getAnnotation(BindViews.class);
                if (annotation != null) {
                    int[] viewIds = annotation.value();
                    ArrayList<Object> views = new ArrayList<>();
                    for (int viewId : viewIds) {
                        Object view = bindView.findViewById(viewId);
                        views.add(view);
                    }
                    field.setAccessible(true);
                    try {
                        field.set(target, views);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 给View添加点击事件
     * @param target
     * @param bindView
     */
    private static void bindClickEvent(Object target, View bindView) {
        Class<?> clazz = target.getClass();
        if (clazz != null) {
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                //获取方法上的所有注解
                Annotation[] annotations = method.getAnnotations();
                for (Annotation annotation : annotations) {
                    //获取注解类型
                    Class<? extends Annotation> annotationType = annotation.annotationType();
                    if (annotationType != null) {
                        //获取注解上的注解（EventBase）注解
                        EventBase eventBase = annotationType.getAnnotation(EventBase.class);
                        if (eventBase != null) {
                            //View的设置监听事件的方法如：setOnClickListener, setOnLongClickListener
                            String listenerSetter = eventBase.listenerSetter();
                            //View的监听事件的参数类型如：View.OnClickListener, View.OnLongClickListener
                            Class<?> listenerType = eventBase.listenerType();
                            //View的监听事件回调方法如：onClick, onLongClick
                            String callbackListener = eventBase.callbackListener();
                            try {
                                Method valueMethod = annotationType.getDeclaredMethod("value");
                                int[] viewIds = (int[]) valueMethod.invoke(annotation);
                                ListenerInvocationHandler handler = new ListenerInvocationHandler(target);
                                handler.addMethod(callbackListener, method);
                                //动态代理，拦截listenerType中的方法，在handler中处理
                                Object listener = Proxy.newProxyInstance(listenerType.getClassLoader(), new Class[]{listenerType}, handler);
                                for (int viewId : viewIds) {
                                    View view = bindView.findViewById(viewId);
                                    Method setter = view.getClass().getMethod(listenerSetter, listenerType);
                                    setter.invoke(view, listener);
                                }
                            } catch (NoSuchMethodException e) {
                                e.printStackTrace();
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
    }
}
